//
// Created by amon.huang on 2021/9/11.
//

#include "Push.h"
#include "PushConstDefine.h"

Push::Push(PushJNICall *pJniCall, const char *pushUrl) : pRTMP(nullptr) {
    this->pJniCall = pJniCall;
    this->pPushUrl = static_cast<char *>(malloc(strlen(pushUrl) + 1));
    strcpy(this->pPushUrl, pushUrl);
    this->pPacketQueue = new PushPacketQueue();
}

void *initConnectThread(void *context) {
    Push *pPush = (Push *) context;
    pPush->pRTMP = RTMP_Alloc();
    RTMP_Init(pPush->pRTMP);
    pPush->pRTMP->Link.timeout = 10;
    pPush->pRTMP->Link.lFlags |= RTMP_LF_LIVE;
    RTMP_SetupURL(pPush->pRTMP, pPush->pPushUrl);
    RTMP_EnableWrite(pPush->pRTMP);
    if (!RTMP_Connect(pPush->pRTMP, nullptr)) {
        pPush->pJniCall->onConnectError(PUSH_THREAD_CHILD, -1, "rtmp 连接出错");
        return (void *) -1;
    }

    if (!RTMP_ConnectStream(pPush->pRTMP, 0)) {
        pPush->pJniCall->onConnectError(PUSH_THREAD_CHILD, -2, "rtmp 连接流出错");
        return (void *) -2;
    }
    pPush->pJniCall->onConnectSuccess(PUSH_THREAD_CHILD);
    pPush->startTime = RTMP_GetTime();
    while (pPush->isPush) {
        RTMPPacket *packet = pPush->pPacketQueue->pop();
        if (packet) {
            int ret = RTMP_SendPacket(pPush->pRTMP, packet, 1);
            LOGE("ret:%d", ret);
            RTMPPacket_Free(packet);
            free(packet);
        }
    }
    return (void *) nullptr;
}

void Push::initConnect() {
    pthread_create(&initThreadId, nullptr, &initConnectThread, this);
}

Push::~Push() {
    if (this->pPushUrl) {
        free(this->pPushUrl);
    }
    if (this->pPacketQueue) {
        delete pPacketQueue;
        this->pPacketQueue = nullptr;
    }
    if (this->pRTMP) {
        RTMP_Close(pRTMP);
        RTMP_Free(this->pRTMP);
    }
}

void Push::pushSpsPps(uint8_t *sps, uint16_t spsLength, uint8_t *pps, uint16_t ppsLength) {
    // frame type : 1关键帧，2 非关键帧 (4bit)
    // CodecID : 7表示 AVC (4bit)  , 与 frame type 组合起来刚好是 1 个字节  0x17
    // fixed : 0x00 0x00 0x00 0x00 (4byte)
    // configurationVersion  (1byte)  0x01版本
    // AVCProfileIndication  (1byte)  sps[1] profile
    // profile_compatibility (1byte)  sps[2] compatibility
    // AVCLevelIndication    (1byte)  sps[3] Profile level
    // lengthSizeMinusOne    (1byte)  0xff   包长数据所使用的字节数

    // sps + pps 的数据
    // sps number            (1byte)  0xe1   sps 个数
    // sps data length       (2byte)  sps 长度
    // sps data                       sps 的内容
    // pps number            (1byte)  0x01   pps 个数
    // pps data length       (2byte)  pps 长度
    // pps data                       pps 的内容

    // 数据的长度（大小） = sps 大小 + pps 大小 + 16字节
    int bodySize = spsLength + ppsLength + 16;
    // 构建 RTMPPacket
    RTMPPacket *pPacket = (RTMPPacket *) malloc(sizeof(RTMPPacket));
    RTMPPacket_Alloc(pPacket, bodySize);
    RTMPPacket_Reset(pPacket);

    // 构建 body 按上面的一个一个开始赋值
    char *body = pPacket->m_body;
    int index = 0;
    // CodecID : 7表示 AVC (4bit)  , 与 frame type 组合起来刚好是 1 个字节  0x17
    body[index++] = 0x17;
    // fixed : 0x00 0x00 0x00 0x00 (4byte)
    body[index++] = 0x00;
    body[index++] = 0x00;
    body[index++] = 0x00;
    body[index++] = 0x00;
    // configurationVersion  (1byte)  0x01版本
    body[index++] = 0x01;
    // AVCProfileIndication  (1byte)  sps[1] profile
    body[index++] = sps[1];
    // profile_compatibility (1byte)  sps[2] compatibility
    body[index++] = sps[2];
    // AVCLevelIndication    (1byte)  sps[3] Profile level
    body[index++] = sps[3];
    // lengthSizeMinusOne    (1byte)  0xff   包长数据所使用的字节数
    body[index++] = 0xff;
    // sps + pps 的数据
    // sps number            (1byte)  0xe1   sps 个数
    body[index++] = 0xe1;
    // sps data length       (2byte)  sps 长度
    body[index++] = (spsLength >> 8) & 0xFF;
    body[index++] = spsLength & 0xFF;
    // sps data                       sps 的内容
    memcpy(&body[index], sps, spsLength);
    index += spsLength;
    // pps number            (1byte)  0x01   pps 个数
    body[index++] = 0x01;
    // pps data length       (2byte)  pps 长度
    body[index++] = (ppsLength >> 8) & 0xFF;
    body[index++] = ppsLength & 0xFF;
    // pps data                       pps 的内容
    memcpy(&body[index], pps, ppsLength);

    // RTMPPacket 设置一些信息
    pPacket->m_hasAbsTimestamp = 0;
    pPacket->m_nTimeStamp = 0;
    pPacket->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
    pPacket->m_packetType = RTMP_PACKET_TYPE_VIDEO;
    pPacket->m_nBodySize = bodySize;
    pPacket->m_nChannel = 0x04;
    pPacket->m_nInfoField2 = this->pRTMP->m_stream_id;

    pPacketQueue->push(pPacket);
}

void Push::pushVideoData(uint8_t *videoData, int dataLen, bool keyFrame) {
// frame type : 1关键帧，2 非关键帧 (4bit)
    // CodecID : 7表示 AVC (4bit)  , 与 frame type 组合起来刚好是 1 个字节  0x17
    // fixed : 0x01 0x00 0x00 0x00 (4byte)  0x01  表示 NALU 单元

    // video data length       (4byte)  video 长度
    // video data
    // 数据的长度（大小） =  dataLen + 9
    int bodySize = dataLen + 9;
    // 构建 RTMPPacket
    RTMPPacket *pPacket = (RTMPPacket *) malloc(sizeof(RTMPPacket));
    RTMPPacket_Alloc(pPacket, bodySize);
    RTMPPacket_Reset(pPacket);

    // 构建 body 按上面的一个一个开始赋值
    char *body = pPacket->m_body;
    int index = 0;
    // frame type : 1关键帧，2 非关键帧 (4bit)
    // CodecID : 7表示 AVC (4bit)  , 与 frame type 组合起来刚好是 1 个字节  0x17
    if (keyFrame) {
        body[index++] = 0x17;
    } else {
        body[index++] = 0x27;
    }

    // fixed : 0x01 0x00 0x00 0x00 (4byte)  0x01  表示 NALU 单元
    body[index++] = 0x01;
    body[index++] = 0x00;
    body[index++] = 0x00;
    body[index++] = 0x00;

    // video data length       (4byte)  video 长度
    body[index++] = (dataLen >> 24) & 0xFF;
    body[index++] = (dataLen >> 16) & 0xFF;
    body[index++] = (dataLen >> 8) & 0xFF;
    body[index++] = dataLen & 0xFF;
    // video data
    memcpy(&body[index], videoData, dataLen);

    // RTMPPacket 设置一些信息
    pPacket->m_headerType = RTMP_PACKET_SIZE_LARGE;
    pPacket->m_packetType = RTMP_PACKET_TYPE_VIDEO;
    pPacket->m_hasAbsTimestamp = 0;
    pPacket->m_nTimeStamp = RTMP_GetTime() - startTime;
    pPacket->m_nBodySize = bodySize;
    pPacket->m_nChannel = 0x04;
    pPacket->m_nInfoField2 = this->pRTMP->m_stream_id;

    pPacketQueue->push(pPacket);
}

void Push::pushAudioData(uint8_t *audioData, int dataLen) {
    // 2 字节头信息
    // 前四位表示音频数据格式 AAC  10  ->  1010  ->  A
    // 五六位表示采样率 0 = 5.5k  1 = 11k  2 = 22k  3(11) = 44k
    // 七位表示采样采样的精度 0 = 8bits  1 = 16bits
    // 八位表示音频类型  0 = mono  1 = stereo
    // 我们这里算出来第一个字节是 0xAF   1010   11 11

    // 数据的长度（大小） =  dataLen + 2
    int bodySize = dataLen + 2;
    // 构建 RTMPPacket
    RTMPPacket *pPacket = (RTMPPacket *) malloc(sizeof(RTMPPacket));
    RTMPPacket_Alloc(pPacket, bodySize);
    RTMPPacket_Reset(pPacket);

    // 构建 body 按上面的一个一个开始赋值
    char *body = pPacket->m_body;
    int index = 0;
    // 我们这里算出来第一个字节是 0xAF
    body[index++] = 0xAF;
    // 0x01 代表 aac 原始数据
    body[index++] = 0x01;
    // video data
    memcpy(&body[index], audioData, dataLen);

    // RTMPPacket 设置一些信息
    pPacket->m_headerType = RTMP_PACKET_SIZE_LARGE;
    pPacket->m_packetType = RTMP_PACKET_TYPE_AUDIO;
    pPacket->m_hasAbsTimestamp = 0;
    pPacket->m_nTimeStamp = RTMP_GetTime() - startTime;
    pPacket->m_nBodySize = bodySize;
    pPacket->m_nChannel = 0x04;
    pPacket->m_nInfoField2 = this->pRTMP->m_stream_id;

    pPacketQueue->push(pPacket);
}

void Push::stop() {
    isPush = false;
    pPacketQueue->notify();
    pthread_join(initThreadId, nullptr);
}
